package inabit.data.expression;

import inabit.base.WorkingMemory;

import java.util.ArrayList;
import java.util.List;
/**Represents a logic expression which operator can be 'and' or 'or'
 * @author Rafael Rocha*/
public class LogicExpression extends Expression{
	public static final int AND = 0;
	public static final int OR = 1;
	
	private int operator;
	private Expression left;
	private Expression right;
	
	public LogicExpression(Expression left, int operator, Expression right) {
		this.left = left;
		this.operator = operator;
		this.right = right;
	}
	@Override
	public Expression copy() {
		return new LogicExpression(left, operator, right);
	}
	public Expression getLeftSide() {
		return left;
	}
	public Expression getRightSide() {
		return right;
	}
	public int getOperator() {
		return operator;
	}
	/**Returns a value ranging from 0(false) to 1(true) evaluating
	 * the expressions which are part of this expressions and then applying
	 * the fuzzy operation to 'and' or 'or' using max and min value strategies,
	 * so that it keeps consistent with crisp expressions*/
	@Override
	public Double evaluate(WorkingMemory wm) {
		Double leftTruth = left.evaluate(wm);
		Double rightTruth = right.evaluate(wm);
		Double result = null;
		switch(operator) {
		case AND:
			if(leftTruth != null && rightTruth != null) {
				result = Math.min(left.evaluate(wm), right.evaluate(wm));
			}
			break;
		case OR:
			if(leftTruth == null) return rightTruth;
			if(rightTruth == null) return leftTruth;
			result = Math.max(left.evaluate(wm), right.evaluate(wm));
			break;
		default:
			result = null;
		}
		
		if(result != null) {
			return hasNot()? 1.0 - result : result;
		}
		return null;
	}

	
	@Override
	public String stringForm() {
		String op;
		switch(operator) {
		case AND: op = "<and>";break;
		case OR: op = "<or>";break;
		default: op = "<null>";
		}
		return "( "+left.toString()+" ) " + op + " ( "+right.toString()+" )" ;
	}
	@Override
	public List<String> getReferencedVariablesIds() {
		List<String> referenced = new ArrayList<String>();
		referenced.addAll(left.getReferencedVariablesIds());
		referenced.addAll(right.getReferencedVariablesIds());
		return referenced;
	}
}
